package com.snowfeel.sfmall.database.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.snowfeel.sfmall.core.constants.EntityConstants;
import com.snowfeel.sfmall.database.typehandler.IntegerArrayJsonTypeHandler;
import com.snowfeel.sfmall.database.typehandler.LongArrayJsonTypeHandler;
import com.snowfeel.sfmall.database.typehandler.MyDataPermissionHandler;
import com.snowfeel.sfmall.database.typehandler.StringArrayJsonTypeHandler;
import com.snowfeel.sfmall.security.util.SecurityUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;

/**
 * @author guomenghuai
 * @date 2024/8/24
 * @Description
 */
@Configuration
@MapperScan("com.snowfeel.sfmall.**.mapper")
public class MybatisPlusConfig {

    private final static String CREATETIME_FIELD = "createTime";
    private final static String CREATEUSER_FIELD = "createUser";
    private final static String UPDATETIME_FIELD = "updateTime";
    private final static String UPDATEUSER_FIELD = "updateUser";
    private final static String DELETED_FIELD = "deleted";

    private final static String ET = "et";

    /**
     * 分页插件和数据权限插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //数据权限
        interceptor.addInnerInterceptor(new DataPermissionInterceptor(new MyDataPermissionHandler()));
        //分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));

        return interceptor;
    }

    /**
     * 自定义typeHandler配置
     * @return
     */
    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> {
            // 全局注册自定义TypeHandler
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            typeHandlerRegistry.register(String[].class, JdbcType.OTHER, StringArrayJsonTypeHandler.class);
            typeHandlerRegistry.register(Long[].class, JdbcType.OTHER, LongArrayJsonTypeHandler.class);
            typeHandlerRegistry.register(Integer[].class, JdbcType.OTHER, IntegerArrayJsonTypeHandler.class);
        };
    }

    /**
     * 自动填充配置
     * @return
     */
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MetaObjectHandler() {

            @Override
            public void insertFill(MetaObject metaObject) {
                if (metaObject.hasSetter(CREATETIME_FIELD)) {
                    Object createTime = getFieldValByName(CREATETIME_FIELD, metaObject);
                    if (createTime == null) {
                        Class<?> fieldType = getFieldType(metaObject, CREATETIME_FIELD);
                        if (fieldType.isAssignableFrom(LocalDateTime.class)) {
                            setFieldValByName(CREATETIME_FIELD, LocalDateTime.now(), metaObject);
                        } else if (fieldType.isAssignableFrom(LocalDate.class)) {
                            setFieldValByName(CREATETIME_FIELD, LocalDate.now(), metaObject);
                        } else {
                            setFieldValByName(CREATETIME_FIELD, new Date(), metaObject);
                        }
                    }
                }

                if (metaObject.hasSetter(CREATEUSER_FIELD)) {
                    Object createUser = getFieldValByName(CREATEUSER_FIELD, metaObject);
                    if (createUser == null) {
                        setFieldValByName(CREATEUSER_FIELD, SecurityUtils.getUserId(), metaObject);
                    }
                }

                if (metaObject.hasSetter(DELETED_FIELD)) {
                    Object deleted = getFieldValByName(DELETED_FIELD, metaObject);
                    if (deleted == null) {
                        setFieldValByName(DELETED_FIELD, EntityConstants.NOT_DELETED, metaObject);
                    }
                }

                if (metaObject.hasSetter(UPDATETIME_FIELD)) {
                    Object updateTime = getFieldValByName(UPDATETIME_FIELD, metaObject);
                    if (updateTime == null) {
                        update(metaObject);
                    }
                }

                if (metaObject.hasSetter(UPDATEUSER_FIELD)) {
                    Object updateUser = getFieldValByName(UPDATEUSER_FIELD, metaObject);
                    if (updateUser == null) {
                        setFieldValByName(UPDATEUSER_FIELD, SecurityUtils.getUserId(), metaObject);
                    }

                }
            }

            @Override
            public void updateFill(MetaObject metaObject) {
                if (metaObject.hasSetter(UPDATETIME_FIELD)) {
                    update(metaObject);
                }
                if (metaObject.hasSetter(UPDATEUSER_FIELD)) {
                    setFieldValByName(UPDATEUSER_FIELD, SecurityUtils.getUserId(), metaObject);
                }
            }

            private void update(MetaObject metaObject){
                Class<?> fieldType = getFieldType(metaObject, UPDATETIME_FIELD);
                if (fieldType.isAssignableFrom(LocalDateTime.class)) {
                    setFieldValByName(UPDATETIME_FIELD, LocalDateTime.now(), metaObject);
                } else if (fieldType.isAssignableFrom(LocalDate.class)) {
                    setFieldValByName(UPDATETIME_FIELD, LocalDate.now(), metaObject);
                } else {
                    setFieldValByName(UPDATETIME_FIELD, new Date(), metaObject);
                }
            }
        };
    }

    private Class<?> getFieldType(MetaObject metaObject, String name) {
        if (metaObject.hasSetter(name) && metaObject.hasGetter(name)) {
            return metaObject.getSetterType(name);
        } else if (metaObject.hasGetter(ET)) {
            Object et = metaObject.getValue(ET);
            if (et != null) {
                MetaObject etMeta = SystemMetaObject.forObject(et);
                if (etMeta.hasSetter(name)) {
                    return etMeta.getSetterType(name);
                }
            }
        }
        return Object.class;
    }
}
